//! # 项目初始化命令
//!
//! 用于创建新的 RustCloud 项目

use crate::config::CliConfig;
use crate::error::{CliError, CliResult};
use crate::templates::TemplateEngine;
use crate::utils::fs_utils;
use clap::Args;
use colored::*;
use console::Emoji;
use dialoguer::{Confirm, Input, Select};
use std::path::PathBuf;
use tracing::{info, warn};

static SPARKLE: Emoji<'_, '_> = Emoji("✨ ", "");
static TRUCK: Emoji<'_, '_> = Emoji("🚚 ", "");
static CLIP: Emoji<'_, '_> = Emoji("🔗 ", "");

/// 初始化命令参数
#[derive(Args, Debug)]
pub struct InitArgs {
    /// 项目名称
    pub name: Option<String>,

    /// 项目目录（默认为项目名称）
    #[arg(short, long)]
    pub path: Option<PathBuf>,

    /// 项目模板
    #[arg(short, long)]
    pub template: Option<String>,

    /// 是否跳过交互模式
    #[arg(long)]
    pub non_interactive: bool,

    /// 强制覆盖已存在的目录
    #[arg(short, long)]
    pub force: bool,

    /// 项目描述
    #[arg(long)]
    pub description: Option<String>,

    /// 项目许可证
    #[arg(long)]
    pub license: Option<String>,

    /// 是否私有项目
    #[arg(long)]
    pub private: bool,

    /// Git 仓库 URL
    #[arg(long)]
    pub git: Option<String>,

    /// 跳过 Git 初始化
    #[arg(long)]
    pub no_git: bool,

    /// 初始化后立即安装依赖
    #[arg(long)]
    pub install: bool,
}

/// 项目配置信息
#[derive(Debug, Clone)]
pub struct ProjectConfig {
    /// 项目名称
    pub name: String,
    /// 项目路径
    pub path: PathBuf,
    /// 项目描述
    pub description: String,
    /// 模板类型
    pub template: String,
    /// 作者信息
    pub author: String,
    /// 邮箱
    pub email: String,
    /// 许可证
    pub license: String,
    /// 是否私有
    pub private: bool,
    /// Git 仓库
    pub git_repo: Option<String>,
    /// 是否初始化 Git
    pub init_git: bool,
    /// 是否安装依赖
    pub install_deps: bool,
}

/// 可用的项目模板
#[derive(Debug, Clone)]
pub struct ProjectTemplate {
    /// 模板 ID
    pub id: String,
    /// 显示名称
    pub name: String,
    /// 描述
    pub description: String,
    /// 模板文件路径
    pub path: String,
}

/// 执行初始化命令
pub async fn execute(args: InitArgs, config: CliConfig) -> CliResult<()> {
    println!("{} {}初始化 RustCloud 项目", SPARKLE, "开始".bright_green().bold());

    // 收集项目配置信息
    let project_config = collect_project_info(args, &config).await?;

    // 验证项目配置
    validate_project_config(&project_config)?;

    // 创建项目
    create_project(&project_config, &config).await?;

    println!();
    println!("{} {}项目创建成功！", TRUCK, "完成".bright_green().bold());
    println!();
    println!("项目位置: {}", project_config.path.display().to_string().bright_blue());
    println!("项目名称: {}", project_config.name.bright_yellow());
    println!("使用模板: {}", project_config.template.bright_cyan());

    // 显示后续步骤
    show_next_steps(&project_config)?;

    Ok(())
}

/// 收集项目信息
async fn collect_project_info(args: InitArgs, config: &CliConfig) -> CliResult<ProjectConfig> {
    let templates = get_available_templates(config).await?;

    let (name, path) = get_project_name_and_path(args.name, args.path, args.non_interactive)?;
    let template = get_project_template(args.template, &templates, args.non_interactive)?;
    let description = get_project_description(args.description, args.non_interactive)?;
    let license = get_project_license(args.license, &config.global.repository.license, args.non_interactive)?;

    Ok(ProjectConfig {
        name: name.clone(),
        path,
        description,
        template,
        author: config.global.author.name.clone(),
        email: config.global.author.email.clone(),
        license,
        private: args.private,
        git_repo: args.git,
        init_git: !args.no_git,
        install_deps: args.install,
    })
}

/// 获取项目名称和路径
fn get_project_name_and_path(
    name: Option<String>,
    path: Option<PathBuf>,
    non_interactive: bool,
) -> CliResult<(String, PathBuf)> {
    let project_name = match name {
        Some(name) => name,
        None if non_interactive => {
            return Err(CliError::validation("非交互模式下必须指定项目名称"));
        }
        None => Input::new()
            .with_prompt("项目名称")
            .validate_with(|input: &String| -> Result<(), &str> {
                if input.trim().is_empty() {
                    Err("项目名称不能为空")
                } else if !is_valid_project_name(input) {
                    Err("项目名称只能包含字母、数字、连字符和下划线")
                } else {
                    Ok(())
                }
            })
            .interact()
            .map_err(|_| CliError::UserCancelled)?,
    };

    let project_path = match path {
        Some(path) => path,
        None => std::env::current_dir()?.join(&project_name),
    };

    Ok((project_name, project_path))
}

/// 获取项目模板
fn get_project_template(
    template: Option<String>,
    templates: &[ProjectTemplate],
    non_interactive: bool,
) -> CliResult<String> {
    match template {
        Some(template) => {
            // 验证模板是否存在
            if templates.iter().any(|t| t.id == template) {
                Ok(template)
            } else {
                Err(CliError::validation(format!("未找到模板: {}", template)))
            }
        }
        None if non_interactive => Ok("basic".to_string()), // 默认使用基础模板
        None => {
            let template_names: Vec<String> = templates
                .iter()
                .map(|t| format!("{} - {}", t.name, t.description))
                .collect();

            let selection = Select::new()
                .with_prompt("选择项目模板")
                .items(&template_names)
                .default(0)
                .interact()
                .map_err(|_| CliError::UserCancelled)?;

            Ok(templates[selection].id.clone())
        }
    }
}

/// 获取项目描述
fn get_project_description(
    description: Option<String>,
    non_interactive: bool,
) -> CliResult<String> {
    match description {
        Some(desc) => Ok(desc),
        None if non_interactive => Ok("A new RustCloud microservice".to_string()),
        None => {
            let desc = Input::new()
                .with_prompt("项目描述")
                .default("A new RustCloud microservice".to_string())
                .interact()
                .map_err(|_| CliError::UserCancelled)?;
            Ok(desc)
        }
    }
}

/// 获取项目许可证
fn get_project_license(
    license: Option<String>,
    default_license: &str,
    non_interactive: bool,
) -> CliResult<String> {
    match license {
        Some(license) => Ok(license),
        None if non_interactive => Ok(default_license.to_string()),
        None => {
            let licenses = vec!["MIT", "Apache-2.0", "GPL-3.0", "BSD-3-Clause", "Unlicense"];
            let default_index = licenses.iter().position(|&l| l == default_license).unwrap_or(0);

            let selection = Select::new()
                .with_prompt("选择许可证")
                .items(&licenses)
                .default(default_index)
                .interact()
                .map_err(|_| CliError::UserCancelled)?;

            Ok(licenses[selection].to_string())
        }
    }
}

/// 获取可用模板列表
async fn get_available_templates(_config: &CliConfig) -> CliResult<Vec<ProjectTemplate>> {
    // TODO: 从配置中的模板仓库加载模板
    Ok(vec![
        ProjectTemplate {
            id: "basic".to_string(),
            name: "基础服务".to_string(),
            description: "简单的微服务模板".to_string(),
            path: "templates/basic".to_string(),
        },
        ProjectTemplate {
            id: "web-api".to_string(),
            name: "Web API".to_string(),
            description: "RESTful API 服务模板".to_string(),
            path: "templates/web-api".to_string(),
        },
        ProjectTemplate {
            id: "gateway".to_string(),
            name: "API 网关".to_string(),
            description: "API 网关服务模板".to_string(),
            path: "templates/gateway".to_string(),
        },
        ProjectTemplate {
            id: "worker".to_string(),
            name: "后台工作者".to_string(),
            description: "后台任务处理服务模板".to_string(),
            path: "templates/worker".to_string(),
        },
    ])
}

/// 验证项目配置
fn validate_project_config(config: &ProjectConfig) -> CliResult<()> {
    // 检查项目名称
    if !is_valid_project_name(&config.name) {
        return Err(CliError::validation("无效的项目名称"));
    }

    // 检查项目路径是否已存在
    if config.path.exists() {
        if config.path.is_file() {
            return Err(CliError::already_exists("文件已存在"));
        }
        
        if config.path.is_dir() {
            let entries = std::fs::read_dir(&config.path)
                .map_err(|e| CliError::general(format!("无法读取目录: {}", e)))?;
            
            if entries.count() > 0 {
                warn!("目录 {} 已存在且不为空", config.path.display());
                
                let overwrite = Confirm::new()
                    .with_prompt("目录已存在且不为空，是否继续？")
                    .default(false)
                    .interact()
                    .map_err(|_| CliError::UserCancelled)?;
                
                if !overwrite {
                    return Err(CliError::UserCancelled);
                }
            }
        }
    }

    Ok(())
}

/// 创建项目
async fn create_project(config: &ProjectConfig, cli_config: &CliConfig) -> CliResult<()> {
    info!("开始创建项目: {}", config.name);

    // 创建项目目录
    fs_utils::create_dir_all(&config.path).await?;

    // 初始化模板引擎
    let template_engine = TemplateEngine::new(cli_config)?;

    // 渲染项目模板
    template_engine.render_project(&config.template, config).await?;

    // 初始化 Git 仓库
    if config.init_git {
        init_git_repository(config).await?;
    }

    // 安装依赖
    if config.install_deps {
        install_dependencies(config).await?;
    }

    Ok(())
}

/// 初始化 Git 仓库
async fn init_git_repository(config: &ProjectConfig) -> CliResult<()> {
    info!("初始化 Git 仓库");

    let repo = git2::Repository::init(&config.path)?;

    // 添加所有文件
    let mut index = repo.index()?;
    index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?;
    index.write()?;

    // 创建初始提交
    let signature = git2::Signature::now(&config.author, &config.email)?;
    let tree_id = index.write_tree()?;
    let tree = repo.find_tree(tree_id)?;

    repo.commit(
        Some("HEAD"),
        &signature,
        &signature,
        "Initial commit",
        &tree,
        &[],
    )?;

    // 设置远程仓库
    if let Some(git_url) = &config.git_repo {
        repo.remote("origin", git_url)?;
    }

    println!("{} Git 仓库初始化完成", CLIP);
    Ok(())
}

/// 安装项目依赖
async fn install_dependencies(config: &ProjectConfig) -> CliResult<()> {
    info!("安装项目依赖");

    let output = tokio::process::Command::new("cargo")
        .arg("check")
        .current_dir(&config.path)
        .output()
        .await?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        return Err(CliError::general(format!("依赖安装失败: {}", stderr)));
    }

    println!("{} 依赖安装完成", TRUCK);
    Ok(())
}

/// 显示后续步骤
fn show_next_steps(config: &ProjectConfig) -> CliResult<()> {
    println!("后续步骤:");
    println!("  1. 进入项目目录:");
    println!("     {}", format!("cd {}", config.path.display()).bright_blue());
    println!();
    println!("  2. 构建项目:");
    println!("     {}", "cargo build".bright_blue());
    println!();
    println!("  3. 运行项目:");
    println!("     {}", "cargo run".bright_blue());
    println!();
    if !config.install_deps {
        println!("  4. 安装依赖:");
        println!("     {}", "cargo check".bright_blue());
        println!();
    }
    println!("  🎉 开始您的 RustCloud 之旅吧！");
    println!();

    Ok(())
}

/// 验证项目名称是否有效
fn is_valid_project_name(name: &str) -> bool {
    !name.is_empty()
        && name
            .chars()
            .all(|c| c.is_alphanumeric() || c == '-' || c == '_')
        && !name.starts_with('-')
        && !name.ends_with('-')
}